package class35;

import org.omg.PortableServer.POA;

import java.util.HashMap;
import java.util.Map;

/**
 * @author zhangchaoliang
 * create 2022
 */
public class MaxPointsOneLine {

    public static int gcd(int a, int b) {
        return b == 0 ? a : gcd(b, a % b);
    }

    public static int maxPoints1(int[] arrx, int[] arry) {
        if (arrx == null || arrx.length == 0 || arry == null || arry.length == 0) {
            return 0;
        }
        if (arrx.length <= 2) {
            return arrx.length;
        }

        //斜率
        //k:x_y   v:int
        HashMap<String, Integer> map = new HashMap<>();
        //结果
        int res = 0;

        for (int i = 0; i < arrx.length; i++) {
            map.clear();
            map.put("_", 0);
            String key = "_";
            //共点
            int point = 1;
            //共x
            int xNum = 0;
            //共y
            int yNum = 0;
            int maxKey = 0;

            for (int j = i + 1; j < arrx.length; j++) {
                int x = arrx[i];
                int y = arry[i];
                if (x == arrx[j] && y == arry[j]) {
                    //共点
                    point++;
                } else if (y == arry[j]) {
                    xNum++;
                } else if (x == arrx[j]) {
                    yNum++;
                } else {
                    //存在斜率
                    int tempX = arrx[j] - x;
                    int tempY = arry[j] - y;
                    int gcd = gcd(tempX, tempY);
                    int kX = tempX / gcd;
                    int kY = tempY / gcd;
                    key = kX + "_" + kY;
                    if (!map.containsKey(key)) {
                        map.put(key, 1);
                    } else {
                        map.put(key, map.get(key) + 1);
                    }
                    maxKey = Math.max(maxKey, map.get(key));
                }

            }
            res = Math.max(res,
                    Math.max(xNum, Math.max(yNum, maxKey)) + point
            );
        }
        return res;
    }


    public static class Point {
        public int x;
        public int y;

        Point() {
            x = 0;
            y = 0;
        }

        Point(int a, int b) {
            x = a;
            y = b;
        }
    }


    public static int maxPoints2(Point[] points) {
        if (points == null) {
            return 0;
        }
        if (points.length <= 2) {
            return points.length;
        }
        Map<Integer, Map<Integer, Integer>> map = new HashMap<>();
        int result = 0;
        for (int i = 0; i < points.length; i++) {
            map.clear();
            int samePosition = 1;
            int sameX = 0;
            int sameY = 0;
            int line = 0;
            for (int j = i + 1; j < points.length; j++) {
                int x = points[j].x - points[i].x;
                int y = points[j].y - points[i].y;
                if (x == 0 && y == 0) {
                    samePosition++;
                } else if (x == 0) {
                    sameX++;
                } else if (y == 0) {
                    sameY++;
                } else {
                    int gcd = gcd(x, y);
                    x /= gcd;
                    y /= gcd;
                    if (!map.containsKey(x)) {
                        map.put(x, new HashMap<Integer, Integer>());
                    }
                    if (!map.get(x).containsKey(y)) {
                        map.get(x).put(y, 0);
                    }
                    map.get(x).put(y, map.get(x).get(y) + 1);
                    line = Math.max(line, map.get(x).get(y));
                }
            }
            result = Math.max(result, Math.max(Math.max(sameX, sameY), line) + samePosition);
        }
        return result;
    }


    public static Point[] ToShift(int[] arrx, int[] arry) {
        if (arrx == null || arrx.length == 0 || arry == null || arry.length == 0) {
            return null;
        }
        Point[] res = new Point[arrx.length];
        for (int i = 0; i < arrx.length; i++) {
            Point temp = new Point(arrx[i], arry[i]);
            res[i] = temp;
        }
        return res;
    }

    public static int[] generateRandomArray(int maxSize, int maxValue) {
        int[] arr = new int[maxSize];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) ((maxValue + 1) * Math.random());
        }
        return arr;
    }

    public static int[] copyArray(int[] arr) {
        if (arr == null) {
            return null;
        }
        int[] res = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            res[i] = arr[i];
        }
        return res;
    }

    public static void printArray(int[] arr) {
        if (arr == null) {
            return;
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        int maxSize = 20;
        int maxValue = 200;
        int testTime = 500000;
        System.out.println("test begin!");
        for (int i = 0; i < testTime; i++) {
            int[] arrX1 = generateRandomArray(maxSize, maxValue);
            int[] arrY1 = generateRandomArray(maxSize, maxValue);
            int[] arrX2 = copyArray(arrX1);
            int[] arrY2 = copyArray(arrY1);
            int res1 = maxPoints1(arrX1, arrY1);
            Point[] points = ToShift(arrX2, arrY2);
            int res2 = maxPoints2(points);

            if (res1 != res2) {
                System.out.println("Oops!");
                printArray(arrX1);
                printArray(arrY1);
                System.out.println(res1);
                System.out.println(res2);
                break;
            }
        }
        System.out.println("test end!");
    }
}
